package cn.buk.tms.dao;

import cn.buk.common.sc.CommonSearchCriteria;
import cn.buk.tms.entity.misc.AmountHistory;
import cn.buk.tms.entity.misc.EnterpriseBalance;
import cn.buk.tms.entity.misc.PaymentOrder;

import java.util.ArrayList;
import java.util.List;

import jakarta.persistence.criteria.*;
import jakarta.transaction.Transactional;

import cn.buk.tms.entity.misc.PaymentOrder_;
import org.springframework.stereotype.Component;

/**
 * @author yfdai
 */
@Component
@Transactional
public class PaymentOrderDaoImpl extends AbstractDao implements PaymentOrderDao {

	/**
	 * 支付宝在线支付收取的手续费率
	 */
	private static final  double ALIPAY_RATE = 0.015;

	@Override
	public int create(PaymentOrder order) {
		int returnCode = 0;
		if (order == null) {
			throw new IllegalArgumentException("order cannot be null");
		}

		em.persist(order);


		returnCode = 1;

		return returnCode;
	}


	@Override
	public PaymentOrder updatePaymentOrderDone(String orderId, int status, String alipayTradeNo, String alipayBuyerEmail, String alipayBuyerId) {
		if (status != PaymentOrder.PAYMENT_ORDER_SUCCESS) {
      return null;
    }

		PaymentOrder result = null;


		List<PaymentOrder> orders =
				em.createQuery("select o from PaymentOrder o where o.tradeNo = :tradeNo and o.status = :status", PaymentOrder.class)
						.setParameter("tradeNo", orderId)
						.setParameter("status", PaymentOrder.PAYMENT_ORDER_WAITING_FOR_PAYMENT)
						.getResultList();
		if (orders == null || orders.isEmpty()) {
      return null;
    }

		result = orders.get(0);


		if (result.getStatus() != status) {
			//内部计算全部转化为分
			final int realPrice = (int) (result.getPrice() * 100 * (1 - ALIPAY_RATE));

			EnterpriseBalance entBalance = doGetEnterpriseBalance(result.getEnterpriseId(), em);
      //转为分
			entBalance.incCashBalance(realPrice);
			em.merge(entBalance);

			result.setStatus(status);
			result.setAlipayTradeNo(alipayTradeNo);
			result.setAlipayBuyerEmail(alipayBuyerEmail);
			result.setAlipayBuyerId(alipayBuyerId);
			em.merge(result);

			AmountHistory amountHistory = new AmountHistory();
			amountHistory.setEnterpriseId(result.getEnterpriseId());
			amountHistory.setCredit(realPrice);
			amountHistory.setRemark("支付宝充值");
			amountHistory.setOrderType(100);
			amountHistory.setAccountBalance(entBalance.getCashBalance());
			em.persist(amountHistory);

		}

		return result;
	}


	@Override
	public List<PaymentOrder> searchPaymentOrder(final int ownerId, final int enterpriseId, CommonSearchCriteria sc) {
		List<PaymentOrder> results = null;

		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<PaymentOrder> cq = cb.createQuery(PaymentOrder.class);
		Root<PaymentOrder> root = cq.from(PaymentOrder.class);
		root.alias("o");

		var predicates0 = getPredicates_searchPaymentOrder(ownerId, enterpriseId, sc, cb, root);


		// count items
		CriteriaQuery<Long> countCq = cb.createQuery(Long.class);
		Root<PaymentOrder> countRoot = countCq.from(PaymentOrder.class);
		countRoot.alias("o");

		var predicates1 = getPredicates_searchPaymentOrder(ownerId, enterpriseId, sc, cb, countRoot);

		countCq.select(cb.count(countRoot)).where(predicates1.toArray(new Predicate[predicates1.size()]));
		Long count = em.createQuery(countCq).getSingleResult();


		if (count > 0) {
			sc.getPage().setRowCount(count.intValue());

			//search block
			int firstPosition = (sc.getPage().getPageNo() - 1) * sc.getPage().getPageSize();
			cq.select(root).where(predicates0.toArray(new Predicate[predicates0.size()]));

			List<Order> orderByes = new ArrayList<>();
			orderByes.add(cb.desc(root.get("id")));
			cq.orderBy(orderByes);

			sc.getPage().setRowCount(count.intValue());

			results = em.createQuery(cq)
					.setFirstResult(firstPosition)
					.setMaxResults(sc.getPageSize()).getResultList();

		}
		if (results == null) {
      results = new ArrayList<>();
    }
		return results;
	}

	private static List<Predicate> getPredicates_searchPaymentOrder(int ownerId, int enterpriseId, CommonSearchCriteria sc, CriteriaBuilder cb, Root<PaymentOrder> root) {
		List<Predicate> predicates = new ArrayList<>();

		Predicate predicate = cb.conjunction();
		predicates.add(predicate);

		predicate = cb.equal(root.get(PaymentOrder_.ownerEnterpriseId), ownerId);
		predicates.add(predicate);


		if (enterpriseId > 0) {
			predicate = cb.equal(root.get(PaymentOrder_.enterpriseId), enterpriseId);
			predicates.add(predicate);
		}

		if (sc.getStatus() == PaymentOrder.PAYMENT_ORDER_SUCCESS) {
			predicate = cb.equal(root.get(PaymentOrder_.status), sc.getStatus());
			predicates.add(predicate);
		}
		return predicates;
	}

}
